#include <p18f25k20.h>
#include <stdlib.h>
#include <string.h>
#include "Initializations.h"
#include "Delays.h"
#include "Nokia_LCD_controls.h"
#include "globals.h"
#include "System_Functions.h"
#include "Debug_Menu.h"


//--------------------------------------------------------------------------
//		System Functions
//--------------------------------------------------------------------------




void EEPROM_write(unsigned char address, unsigned char data)
{
    EEPROM_read(address);   //as a precaution so that the EEPROM isn't still busy

    EEADR = address;        //set the EEPROM data address
    EEDATA = data;          //prepare the data to be written to the EEPROM

    EECON1bits.EEPGD = 0;   //Point to Data memory
    EECON1bits.CFGS = 0;    //Access EEPROM

    EECON1bits.WREN = 1;   //Enable EEPROM writes
    INTCONbits.GIE = 0;     //Disable all interrupts during EEPROM writes

    EECON2 = 0x55;          //required sequence to start the
    EECON2 = 0xAA;          // EEPROM write
    EECON1bits.WR = 1;      //
    
    

    EECON1bits.WREN = 0;    //Disable EEPROM writes, so nothing erroneous happens
    INTCONbits.GIE = 1;     //Enable all interrupts again

    while(!PIR2bits.EEIF);  //Wait here until the EEPROM write is complete
    PIR2bits.EEIF = 0;      //Clear the complete flag bit

    milliseconds(50);

    EEADR = 0xFF;       //set to some random number, just in case

    return;
}



void EEPROM_write_with_check(unsigned char address, unsigned char data)
{
    EEPROM_read(address);   //as a precaution so that the EEPROM isn't still busy

    EEADR = address;        //set the EEPROM data address
    EEDATA = data;          //prepare the data to be written to the EEPROM

    EECON1bits.EEPGD = 0;   //Point to Data memory
    EECON1bits.CFGS = 0;    //Access EEPROM

    EECON1bits.WREN = 1;   //Enable EEPROM writes
    INTCONbits.GIE = 0;     //Disable all interrupts during EEPROM writes

    EECON2 = 0x55;          //required sequence to start the
    EECON2 = 0xAA;          // EEPROM write
    EECON1bits.WR = 1;      //



    EECON1bits.WREN = 0;    //Disable EEPROM writes, so nothing erroneous happens
    INTCONbits.GIE = 1;     //Enable all interrupts again

    while(!PIR2bits.EEIF);  //Wait here until the EEPROM write is complete
    PIR2bits.EEIF = 0;      //Clear the complete flag bit

    milliseconds(50);

    EEADR = 0xFF;           //Just in case

    EEPROM_value_check(address, data);

    return;
}




unsigned char EEPROM_read(unsigned char address)
{
    EEADR = address;        //Set data address to read
    EECON1bits.EEPGD = 0;   //Point to Data memory
    EECON1bits.CFGS = 0;    //Access EEPROM
    EECON1bits.RD = 1;      //EEPROM read

    return(EEDATA);         //Return the value in EEDATA
}









void cycle_start_check(void)
{
    unsigned char counter = 0;
    //If the manual switch is pressed, or the start time is
        //  equal to the current time, and the runtime minutes are
        //  greater than zero, then check the hose switches, and
        //  if they are present, then set the flag to start the cycle
        //  It also checks to make sure the cycle finished flag is not set,
        //  so that that user has to remove the hoses before another cycle will run
        if((start_time_minutes_global == current_time_minutes || !MANUAL_SW) && runtime_minutes_global > 0 && start_cycle == 0 && !cycle_finished)
        {
            //If the manual sw has been pressed, then debounce
            //  the switch, and wait for it to be released
            if(!MANUAL_SW)
            {
                //Debounce the manual switch, then while the manual
                //  switch is still pressed, every 50 milliseconds
                //  check to see if the start set switch is pressed.
                //  If it is, increment a counter
                milliseconds(DEBOUNCE_TIME);
                while(!MANUAL_SW)
                {
                    milliseconds(50);
                    if(!START_SET_SW)
                    {
                        counter++;
                        if(counter >= 60)
                        {
                            break;  //if 3 seconds have passed, then move on
                        }
                    }
                    else
                    {
                        counter = 0;
                    }
                }

                //If the counter is greater than 60, then the switches
                //  have been pressed for more than 3 seconds, so go to the
                //  reset filter counter routine
                if(counter >= 60)
                {
                    reset_filter_counter();
                    start_cycle = 0;
                    return;
                }

            }

            //If the hose switch is not pressed, then display a message to
            //  the user for 5 seconds, telling them the hose is not present
            if(HOSE_SW)
            {
                LCD_clear();
                LCD_write(LCD_COMMAND, LCD_YADDR(1));
                LCD_write(LCD_COMMAND, LCD_XADDR(2));
                LCD_string("Hose not present");
                LCD_write(LCD_COMMAND, LCD_YADDR(3));
                LCD_write(LCD_COMMAND, LCD_XADDR(0));
                LCD_string("    Cycle will");
                LCD_write(LCD_COMMAND, LCD_YADDR(4));
                LCD_write(LCD_COMMAND, LCD_XADDR(0));
                LCD_string("     not run");
                milliseconds(5000);
                LCD_clear();

                parse_time_minutes();
                update_clock(1);        //with the frame
                parse_start_time_minutes();
                update_start_time();
                update_runtime_mins();
            }

            //If the external hose switch is not pressed, then display a message to
            //  the user for 5 seconds, telling them the external hose is not present
            else if(EXT_HOSE_SW)
            {
                LCD_clear();
                LCD_write(LCD_COMMAND, LCD_YADDR(0));
                LCD_write(LCD_COMMAND, LCD_XADDR(0));
                LCD_string("  External hose");
                LCD_write(LCD_COMMAND, LCD_YADDR(1));
                LCD_write(LCD_COMMAND, LCD_XADDR(0));
                LCD_string("   not present");
                LCD_write(LCD_COMMAND, LCD_YADDR(3));
                LCD_write(LCD_COMMAND, LCD_XADDR(0));
                LCD_string("    Cycle will");
                LCD_write(LCD_COMMAND, LCD_YADDR(4));
                LCD_write(LCD_COMMAND, LCD_XADDR(0));
                LCD_string("     not run");
                milliseconds(5000);
                LCD_clear();

                parse_time_minutes();
                update_clock(1);        //with the frame
                parse_start_time_minutes();
                update_start_time();
                update_runtime_mins();
            }

            //If both the hoses are pressed, then start the cycle!
            else
            {
                start_cycle = 1;
            }

        }


    return;
}





void button_check(void)
{
    unsigned char counter = 0;
    
    //If the time set switch is pushed...
        if(!TIME_SET_SW)
        {
            milliseconds(DEBOUNCE_TIME);       //Debounce the switch
            while(!TIME_SET_SW)    //Wait for it to be released
            {
                //if the minus button is pressed, then break this loop and...
                if(!SW_M)
                {
                    break;
                }
            }

            //...if the minus button being pressed is why the loop was broken,
            //  then go into the 24 hour selection screen
            if(!SW_M)
            {
                hour_format_selection();
            }
            //otherwise the time set button has been released, so go to the
            //  time set sequence
            else
            {
                time_set();             //Call the routine for setting the time
            }
        }

        //If the start time set switch is pushed...
        //  Also make sure the plus and minus switches are not pressed
        if(!START_SET_SW && SW_P && SW_M)
        {
            milliseconds(DEBOUNCE_TIME);       //Debounce the switch
            while(!START_SET_SW)   //Wait for it to be released
            {
                    //Check if the manual switch has also been pressed
                    //  for three seconds
                    milliseconds(50);
                    if(!MANUAL_SW)
                    {
                        counter++;
                        if(counter >= 60)
                        {
                            break;  //if 3 seconds have passed, then move on
                        }
                    }
                    else
                    {
                        counter = 0;
                    }
                }

                //If the counter is greater than 60, then the switches
                //  have been pressed for more than 3 seconds, so go to the
                //  reset filter counter routine
                if(counter >= 60)
                {
                    reset_filter_counter();
                    return;
                }



            set_runtime_mins();     //Call the routine for setting run time
                                    // and start time
        }


        //Pushing the plus switch, minus switch, and start time set switch
        //  enters the debug menu
        if(!SW_P && !SW_M && !START_SET_SW)
        {
            milliseconds(DEBOUNCE_TIME);
            while(!SW_P || !SW_M || !START_SET_SW);
            

            debug_menu();

        }


    return;
}








#pragma interrupt_level 1
void update_clock(unsigned char draw_frame)
{
    unsigned char shift_value = 0;

    if(hours_24)
    {
        shift_value = CLOCK_24H_SHIFT;
    }
    else
    {
        shift_value = 0;
    }

    if(current_ten_hours == 0)
    {
        LCD_current_time(current_ten_hours, THOUR, CLEAR);
    }
    else
    {
        LCD_current_time(current_ten_hours, THOUR, DRAW);
    }

    LCD_current_time(current_hours, HOUR, DRAW);
    LCD_current_time(current_ten_minutes, TMIN, DRAW);
    LCD_current_time(current_minutes, MIN, DRAW);

    /* Draw the colon */
    LCD_write(LCD_COMMAND, LCD_YADDR(0));
    LCD_write(LCD_COMMAND, LCD_XADDR(36 + shift_value));

    LCD_write(LCD_DATA, 0xE0);
    LCD_write(LCD_DATA, 0xE0);
    LCD_write(LCD_DATA, 0xE0);

    LCD_write(LCD_COMMAND, LCD_YADDR(1));
    LCD_write(LCD_COMMAND, LCD_XADDR(36 + shift_value));

    LCD_write(LCD_DATA, 0x80);
    LCD_write(LCD_DATA, 0x80);
    LCD_write(LCD_DATA, 0x80);

    LCD_write(LCD_COMMAND, LCD_YADDR(2));
    LCD_write(LCD_COMMAND, LCD_XADDR(36 + shift_value));

    LCD_write(LCD_DATA, 0x03);
    LCD_write(LCD_DATA, 0x03);
    LCD_write(LCD_DATA, 0x03);

    /* Draw the AM or PM */
    //but only if it's not 24 hour mode
    if(!hours_24)
    {
        LCD_am_pm();
    }

    if(draw_frame)
    {
        LCD_draw_frame();
    }

    update = 0;     //it's been updated, so reset this flag

    return;
}





void parse_time_minutes(void)
{
    unsigned char minutes = 0;
    unsigned char hours = 0;


    /* If the current time has been decremented below 0 minutes, then
       be sure to reset the time to 1439 minutes, or 11:59 pm*/
    if(current_time_minutes < 0)
    {
        current_time_minutes = 1439;
    }

    /* If the current minutes is greater than 1439, then it's rolled over
       to 12:00 AM, so reset the minutes to 0 */
    if(current_time_minutes > 1439)
    {
        current_time_minutes = 0;
    }

    /* check to see if it's AM or PM.  11:59 am = 719 minutes */
    if(current_time_minutes > 719)
    {
        am_pm = 1;          //set it to PM
    }
    else
    {
        am_pm = 0;          //Otherwise it's AM still
    }

    /* first calculate the current hours and minutes, from the total minutes */
    hours = current_time_minutes / 60;              //gives current hour
    minutes = current_time_minutes - (hours * 60);  //solves for current minutes

    /* If the calculated hours is greater than 12, and we're not in
       24 hour format, then convert to 12 hour format*/
    if(hours > 12 && !hours_24)
    {
        hours = hours - 12;
    }

    /* If the hours are zero, and we're not in 24 hour format, then that
       means we're at 12 am */
    if(hours == 0 && !hours_24)
    {
        hours = 12;
    }

    current_ten_minutes = minutes / 10;
    current_minutes = minutes - (current_ten_minutes * 10);

    current_ten_hours = hours / 10;
    current_hours = hours - (current_ten_hours * 10);

    return;
}





//void parse_time(void)
//{
//    if(current_seconds == 60)
//        {
//            current_seconds = 0;    //if one minute has passed, reset the
//            current_minutes++;      // seconds, and increment the minutes
//            current_time_minutes++; //also keep track of the time of day in minutes
//            update = 1;
//        }
//
//        if(current_minutes == 10)
//        {
//            current_minutes = 0;    //if 10 minutes have passed, reset the
//            current_ten_minutes++;  // minutes and increment the ten minutes
//            update = 1;
//        }
//
//        if(current_ten_minutes == 6)
//        {
//            current_ten_minutes = 0;    //if 6 ten-minutes have passed, reset the
//            current_hours++;            // ten minutes, and increment the hours
//            current_hours_count++;      //kludgy way to find AM or PM
//            update = 1;
//        }
//
//
//        if(current_hours == 10)
//        {
//            current_hours = 0;      //if 10 hours have passed, reset the
//            current_ten_hours++;    // hours and increment the ten hours
//            update = 1;
//        }
//
//        /*
//            If current ten hours is 1, and current hours reaches 3,
//             then it's time to roll over to 1pm or 1am
//         */
//        if(current_ten_hours == 1 && current_hours == 3)
//        {
//            current_ten_hours = 0;
//            current_hours = 1;
//            update = 1;
//        }
//
//
//        if(current_hours_count > 11)
//        {
//            am_pm = 1;
//        }
//        else
//        {
//            am_pm = 0;
//        }
//
//
//        if(current_hours_count == 24)
//        {
//            current_hours_count = 0;
//        }
//
//
//    return;
//}





void time_set(void)
{
    int counter = 0;
    unsigned char delay_time = 50;
    unsigned char backlight_count_temp = 0;

    //save the current backlight time, and set the backlight
    // to never go off, while it's in this menu
    backlight_count_temp = backlight_seconds_count;
    backlight_seconds_count = 255;

    LCD_BACKLIGHT = 1;

    T1CONbits.TMR1ON = 0;       //Turn off the timer, so it can be set
    PIE1bits.TMR1IE = 0;        //Turn off the RTC interrupt for now, so nothing
                                //  messed up on accident
    PIR1bits.TMR1IF = 0;       //Just in case it's been set, clear it to restart things
    TMR1L = 0x00;               //Reset the timer, so it starts at 0 once
    TMR1H = 0x80;               // the user has set the time

    update = 0;                 //Also make sure that you don't update right away

    current_seconds = 0;        //Set this to zero, because there will be some
                                // seconds already counted up!!  This is what
                                // confused me, as to how this thing could be several
                                // seconds different from when I initially start the clock
                                // versus my reference clock!  Mystery solved

    LCD_clear();

    update_clock(0);    //do not draw the frame

    LCD_write(LCD_COMMAND, LCD_YADDR(4));
    LCD_write(LCD_COMMAND, LCD_XADDR(0));
    
    LCD_string("Set Current Time");


    while(TIME_SET_SW)
    {
        if(!SW_P)
        {
            while(!SW_P)
            {
                if(counter < DELAY_COUNT1)
                {
                    delay_time = DELAY1;
                }
                else if(counter < DELAY_COUNT2)
                {
                    delay_time = DELAY2;
                }
                else if(counter > DELAY_COUNT2)
                {
                    delay_time = DELAY3;
                }

                current_time_minutes++;
                parse_time_minutes();
                update_clock(0);    //do not draw the frame

                milliseconds(delay_time);

                counter++;

            } // end while(!SW_P)

        } // end if(!SW_P)

        if(!SW_M)
        {
            while(!SW_M)
            {
                if(counter < DELAY_COUNT1)
                {
                    delay_time = DELAY1;
                }
                else if(counter < DELAY_COUNT2)
                {
                    delay_time = DELAY2;
                }
                else if(counter > DELAY_COUNT2)
                {
                    delay_time = DELAY3;
                }

                current_time_minutes = current_time_minutes - 1;
                parse_time_minutes();
                update_clock(0);        //do not draw the frame

                milliseconds(delay_time);

                counter++;

            } // end while(!SW_M)
        } // end if(!SW_M)




        counter = 0;
        
    }


    milliseconds(DEBOUNCE_TIME);
    while(!TIME_SET_SW);

    LCD_clear();
    update_clock(1);        //now draw the frame again
    update_start_time();
    update_runtime_mins();
    LCD_draw_frame();

    //restore the proper backlight time, and make sure the
    // counter is properly set
    backlight_seconds_count = backlight_count_temp;
    backlight_seconds_counter = backlight_seconds_count;

    PIE1bits.TMR1IE = 1;        //Turn the RTC interrupt back on
    T1CONbits.TMR1ON = 1;       //Turn the RTC back on again

    return;
}





void hour_format_selection(void)
{
    unsigned char delay_time = 50;
    unsigned char backlight_count_temp = 0;

    //save the current backlight time, and set the backlight
    // to never go off, while it's in this menu
    backlight_count_temp = backlight_seconds_count;
    backlight_seconds_count = 255;

    LCD_BACKLIGHT = 1;

    T1CONbits.TMR1ON = 0;       //Turn off the timer, so it can be set
    PIE1bits.TMR1IE = 0;        //Turn off the RTC interrupt for now, so nothing
                                //  messed up on accident
    PIR1bits.TMR1IF = 0;       //Just in case it's been set, clear it to restart things
    TMR1L = 0x00;               //Reset the timer, so it starts at 0 once
    TMR1H = 0x80;               // the user has set the time

    update = 0;                 //Also make sure that you don't update right away

    LCD_clear();



    LCD_write(LCD_COMMAND, LCD_YADDR(0));
    LCD_write(LCD_COMMAND, LCD_XADDR(0));

    LCD_string("Time Format:");

    if(hours_24)
    {
        LCD_write(LCD_COMMAND, LCD_YADDR(4));
        LCD_write(LCD_COMMAND, LCD_XADDR(23));

        LCD_write(LCD_DATA, 0x7F);
        LCD_write(LCD_DATA, 0x3E);
        LCD_write(LCD_DATA, 0x1C);
        LCD_write(LCD_DATA, 0x08);
    }
    else
    {
        LCD_write(LCD_COMMAND, LCD_YADDR(2));
        LCD_write(LCD_COMMAND, LCD_XADDR(23));

        LCD_write(LCD_DATA, 0x7F);
        LCD_write(LCD_DATA, 0x3E);
        LCD_write(LCD_DATA, 0x1C);
        LCD_write(LCD_DATA, 0x08);
    }

    LCD_write(LCD_COMMAND, LCD_YADDR(2));
    LCD_write(LCD_COMMAND, LCD_XADDR(30));
    LCD_string("12h");

    LCD_write(LCD_COMMAND, LCD_YADDR(4));
    LCD_write(LCD_COMMAND, LCD_XADDR(30));
    LCD_string("24h");


    milliseconds(DEBOUNCE_TIME);
    while(!TIME_SET_SW);        //wait until the butotn is released

    while(TIME_SET_SW)
    {
        if(!SW_P || !SW_M)
        {
            milliseconds(DEBOUNCE_TIME);
            while(!SW_P || !SW_M);  //wait for button release

            hours_24 = !hours_24;

            if(hours_24)
            {
                //remove the arrow from the 12
                LCD_write(LCD_COMMAND, LCD_YADDR(2));
                LCD_write(LCD_COMMAND, LCD_XADDR(23));

                LCD_write(LCD_DATA, 0x00);
                LCD_write(LCD_DATA, 0x00);
                LCD_write(LCD_DATA, 0x00);
                LCD_write(LCD_DATA, 0x00);

                //display an arrow next to the 24h
                LCD_write(LCD_COMMAND, LCD_YADDR(4));
                LCD_write(LCD_COMMAND, LCD_XADDR(23));

                LCD_write(LCD_DATA, 0x7F);
                LCD_write(LCD_DATA, 0x3E);
                LCD_write(LCD_DATA, 0x1C);
                LCD_write(LCD_DATA, 0x08);
            }
            else
            {
                //remove the arrow from the 24h
                LCD_write(LCD_COMMAND, LCD_YADDR(4));
                LCD_write(LCD_COMMAND, LCD_XADDR(23));

                LCD_write(LCD_DATA, 0x00);
                LCD_write(LCD_DATA, 0x00);
                LCD_write(LCD_DATA, 0x00);
                LCD_write(LCD_DATA, 0x00);

                //display an arrow next to the 12h
                LCD_write(LCD_COMMAND, LCD_YADDR(2));
                LCD_write(LCD_COMMAND, LCD_XADDR(23));

                LCD_write(LCD_DATA, 0x7F);
                LCD_write(LCD_DATA, 0x3E);
                LCD_write(LCD_DATA, 0x1C);
                LCD_write(LCD_DATA, 0x08);
            }



            milliseconds(delay_time);




        } // end if(!SW_P || !SW_M)


    }


    
    EEPROM_write_with_check(HOURS_24_ADDR, (hours_24 & 0xFF));

    //After the EEPROM value is written, just double check that the values
    //  were written to what you expect
    EEPROM_value_check(HOURS_24_ADDR, (hours_24 & 0xFF));




    milliseconds(DEBOUNCE_TIME);
    while(!TIME_SET_SW);


    parse_time_minutes();        //do this now, to get time into the 24 hour format
    parse_start_time_minutes();  // or into the 12h format

    LCD_clear();
    update_clock(1);        //now draw the frame again
    update_start_time();
    update_runtime_mins();
    LCD_draw_frame();

    //restore the proper backlight time, and make sure the
    // counter is properly set
    backlight_seconds_count = backlight_count_temp;
    backlight_seconds_counter = backlight_seconds_count;

    PIE1bits.TMR1IE = 1;        //Turn the RTC interrupt back on
    T1CONbits.TMR1ON = 1;       //Turn the RTC back on again

    return;
}








void set_runtime_mins(void)
{
    unsigned char backlight_count_temp = 0;
    unsigned char i = 0;

    //save the current backlight time, and set the backlight
    // to never go off, while it's in this menu
    backlight_count_temp = backlight_seconds_count;
    backlight_seconds_count = 255;

    LCD_clear();
    update_runtime_mins();

    LCD_write(LCD_COMMAND, LCD_YADDR(1));
    LCD_write(LCD_COMMAND, LCD_XADDR(0));

    LCD_string("  Set Run Time");

    LCD_write(LCD_COMMAND, LCD_YADDR(2));
    LCD_write(LCD_COMMAND, LCD_XADDR(0));

    LCD_string("  (in minutes)");

    while(START_SET_SW)
    {
        if(!SW_P)
        {
            /* Don't let the runtime minutes go above the MAX RUNTIME value */
            if(runtime_minutes_global < MAX_RUNTIME)
            {
                runtime_minutes_global++;
            }

            update_runtime_mins();

            milliseconds(10);
            while(!SW_P);
        }

        if(!SW_M)
        {
            /* Don't let the runtime minutes go below 1 */
            if(runtime_minutes_global > 1)
            {
                runtime_minutes_global--;
            }

            update_runtime_mins();

            milliseconds(10);
            while(!SW_M);
        }


    }

    milliseconds(DEBOUNCE_TIME);
    while(!START_SET_SW);

    /* Write the run time minutes to EEPROM, so it can be retrieved
       when the unit is turned back on */
    EEPROM_write_with_check(RUN_TIME_ADDR, runtime_minutes_global);


    /* This loop is to make sure that the run time setting
     * has been written to the EEPROM properly.  This should
     * get rid of the strange bug that shows random gibberish
     * for the run time setting sometimes.
     */
    i = 0;
    while(i < 4)  //do this check only 4 times max, (better not take that many!)
    {
        milliseconds(25);
        //if the re-read EEPROM value is equal to the value that
        //  was supposed to be written, then set i to a value
        //  that will break the loop
        if(EEPROM_read(RUN_TIME_ADDR) == runtime_minutes_global)
        {
            i = 4;
        }

        //If it is not equal, then try to re-write the value to
        //  the EEPROM, and then check again.
        else
        {
            EEPROM_write(RUN_TIME_ADDR, runtime_minutes_global);
            i++;
        }
    }


    LCD_clear();

    
    /* The sequence of things will be...
         Set the run time minutes, then when that is complete,
         set the start time.  Pushing the Start Set button will exit
         whichever function you're in
     */
    set_start_time();


    //restore the proper backlight time, and make sure
    //  the counter is properly set
    backlight_seconds_count = backlight_count_temp;
    backlight_seconds_counter = backlight_seconds_count;

    return;
}






void update_runtime_mins(void)
{
    unsigned char runtime_mins = 0;
    unsigned char runtime_tmins = 0;

    

    runtime_tmins = runtime_minutes_global / 10;
    runtime_mins = runtime_minutes_global - (runtime_tmins * 10);

    LCD_runtime_mins(runtime_tmins, TMIN, DRAW);
    LCD_runtime_mins(runtime_mins, MIN, DRAW);


    return;
}




void parse_start_time_minutes(void)
{
    unsigned char minutes = 0;
    unsigned char hours = 0;


    /* If the current time has been decremented below 0 minutes, then
       be sure to reset the time to 1439 minutes, or 11:59 pm*/
    if(start_time_minutes_global < 0)
    {
        start_time_minutes_global = 1439;
    }

    /* If the current minutes is greater than 1439, then it's rolled over
       to 12:00 AM, so reset the minutes to 0 */
    if(start_time_minutes_global > 1439)
    {
        start_time_minutes_global = 0;
    }

    /* check to see if it's AM or PM.  11:59 am = 719 minutes */
    if(start_time_minutes_global > 719)
    {
        start_am_pm = 1;          //set it to PM
    }
    else
    {
        start_am_pm = 0;          //Otherwise it's AM still
    }

    /* first calculate the current hours and minutes, from the total minutes */
    hours = start_time_minutes_global / 60;              //gives current hour
    minutes = start_time_minutes_global - (hours * 60);  //solves for current minutes

    /* If the calculated hours is greater than 12, and we're not in
       24 hour format, then convert to 12 hour format*/
    if(hours > 12 && !hours_24)
    {
        hours = hours - 12;
    }

    /* If the hours are zero, and we're not in 24 hour format, then that
       means we're at 12 am */
    if(hours == 0 && !hours_24)
    {
        hours = 12;
    }

    start_ten_minutes = minutes / 10;
    start_minutes = minutes - (start_ten_minutes * 10);

    start_ten_hours = hours / 10;
    start_hours = hours - (start_ten_hours * 10);

    return;
}



void update_start_time(void)
{

    if(start_ten_hours == 0)
    {
        LCD_start_time(start_ten_hours, THOUR, CLEAR);
    }
    else
    {
        LCD_start_time(start_ten_hours, THOUR, DRAW);
    }

    LCD_start_time(start_hours, HOUR, DRAW);
    LCD_start_time(start_ten_minutes, TMIN, DRAW);
    LCD_start_time(start_minutes, MIN, DRAW);

    //Draw the AM or PM for the start time only
    //  if it is not in 24 hour mode
    if(!hours_24)
    {
        LCD_start_am_pm();
    }
    

    return;
}



void set_start_time(void)
{
    int counter = 0;
    unsigned char delay_time = 50;
    unsigned char temp = 0;


    LCD_clear();
    update_start_time();

    LCD_write(LCD_COMMAND, LCD_YADDR(1));
    LCD_write(LCD_COMMAND, LCD_XADDR(0));

    LCD_string(" Set Start Time");


    while(START_SET_SW)
    {
        if(!SW_P)
        {
            while(!SW_P)
            {
                if(counter < DELAY_COUNT1)
                {
                    delay_time = DELAY1;
                }
                else if(counter < DELAY_COUNT2)
                {
                    delay_time = DELAY2;
                }
                else if(counter > DELAY_COUNT2)
                {
                    delay_time = DELAY3;
                }

                start_time_minutes_global++;
                parse_start_time_minutes();
                update_start_time();

                milliseconds(delay_time);

                counter++;

            } // end while(!SW_P)

        } // end if(!SW_P)

        if(!SW_M)
        {
            while(!SW_M)
            {
                if(counter < DELAY_COUNT1)
                {
                    delay_time = DELAY1;
                }
                else if(counter < DELAY_COUNT2)
                {
                    delay_time = DELAY2;
                }
                else if(counter > DELAY_COUNT2)
                {
                    delay_time = DELAY3;
                }

                start_time_minutes_global--;
                parse_start_time_minutes();
                update_start_time();

                milliseconds(delay_time);

                counter++;

            } // end while(!SW_M)
        } // end if(!SW_M)




        counter = 0;

    }


    milliseconds(DEBOUNCE_TIME);
    while(!START_SET_SW);

    /* Write the low byte of the start time minutes to EEPROM */
    EEPROM_write_with_check(START_TIME_ADDRL, (start_time_minutes_global & 0xFF));

    /* Shift the start time minutes by 8, and then write the high byte
       of start time minutes to EEPROM */
    temp = (start_time_minutes_global >> 8) & 0xFF;
    EEPROM_write_with_check(START_TIME_ADDRH, temp);


    LCD_clear();
    update_start_time();
    update_runtime_mins();
    
    parse_time_minutes();
    update_clock(1);        //with the frame


    return;
}




void filter_change_reminder(void)
{
    unsigned char backlight_count_temp = 0;
    unsigned char i = 0;

    //This was here because one time the thing froze in this
    //  part of the code, but it hasn't done it since
    INTCONbits.GIEH = 1;		  //turn off all interrupts

    //save the current backlight time, and set the backlight
    // to never go off, while it's in this menu
    backlight_count_temp = backlight_seconds_count;
    backlight_seconds_count = 255;
    

    LCD_BACKLIGHT = 1;
    
    LCD_clear();
    
    LCD_write(LCD_COMMAND, LCD_YADDR(2));
    LCD_write(LCD_COMMAND, LCD_XADDR(29));
    LCD_string("ORDER");
    
    LCD_write(LCD_COMMAND, LCD_YADDR(4));
    LCD_write(LCD_COMMAND, LCD_XADDR(17));
    LCD_string("FILTER KIT");


    for(i=0; i<30; i++)
    {
        GREEN_LEDS = 1;
        RED_LEDS = 1;
        YELLOW_LEDS = 1;

        milliseconds(250);

        GREEN_LEDS = 0;
        RED_LEDS = 0;
        YELLOW_LEDS = 0;

        milliseconds(250);
    }

    LCD_BACKLIGHT = 0;
    
    LCD_clear();
    update_start_time();
    update_runtime_mins();

    parse_time_minutes();
    update_clock(1);        //with the frame

    //restore the proper backlight time, and make sure
    //  the counter is properly set
    backlight_seconds_count = backlight_count_temp;
    backlight_seconds_counter = backlight_seconds_count;

    INTCONbits.GIEH = 1;		  //turn on all interrupts

    return;
}



void reset_filter_counter(void)
{
    unsigned char backlight_count_temp = 0;
    

    //This was here because one time the thing froze in this
    //  part of the code, but it hasn't done it since
    INTCONbits.GIEH = 1;		  //turn off all interrupts

    //save the current backlight time, and set the backlight
    // to never go off, while it's in this menu
    backlight_count_temp = backlight_seconds_count;
    backlight_seconds_count = 255;


    LCD_BACKLIGHT = 1;

    LCD_clear();

    /*
    LCD_write(LCD_COMMAND, LCD_YADDR(1));
    LCD_write(LCD_COMMAND, LCD_XADDR(27));
    LCD_string("FILTER");

    LCD_write(LCD_COMMAND, LCD_YADDR(3));
    LCD_write(LCD_COMMAND, LCD_XADDR(27));
    LCD_string("CHANGE");

    LCD_write(LCD_COMMAND, LCD_YADDR(5));
    LCD_write(LCD_COMMAND, LCD_XADDR(17));
    LCD_string("SUCCESSFUL");
    */

    LCD_splashscreen();

    RED_LEDS = 0;
    YELLOW_LEDS = 0;
    GREEN_LEDS = 1;

    milliseconds(5000);     //Display this message for 5 seconds

    filter_minutes_count = 0;       //reset the filer minutes count to 0!

     /* Write the low byte of the filter count minutes to EEPROM */
     EEPROM_write_with_check(FILTER_MINUTES_COUNT_L, 0x00);

     /* Shift the filter count minutes by 8, and then write the high byte
        of filter count minutes to EEPROM */
     EEPROM_write_with_check(FILTER_MINUTES_COUNT_H, 0x00);

     //After the EEPROM value is written, just double check that the values
     //  were written to what you expect
     EEPROM_value_check(FILTER_MINUTES_COUNT_L, 0x00);
     EEPROM_value_check(FILTER_MINUTES_COUNT_H, 0x00);




    LCD_BACKLIGHT = 0;

    LCD_clear();
    update_start_time();
    update_runtime_mins();

    parse_time_minutes();
    update_clock(1);        //with the frame

    //restore the proper backlight time, and make sure
    //  the counter is properly set
    backlight_seconds_count = backlight_count_temp;
    backlight_seconds_counter = backlight_seconds_count;

    INTCONbits.GIEH = 1;		  //turn on all interrupts


    return;
}


void EEPROM_value_check(unsigned char address, unsigned char value)
{
    /* This loop is to make sure that the run time setting
     * has been written to the EEPROM properly.
     */
    unsigned char i = 0;
    while(i < 4)  //do this check only 4 times max, (better not take that many!)
    {
        milliseconds(25);
        //if the re-read EEPROM value is equal to the value that
        //  was supposed to be written, then set i to a value
        //  that will break the loop
        if(EEPROM_read(address) == value)
        {
            i = 4;
        }

        //If it is not equal, then try to re-write the value to
        //  the EEPROM, and then check again.
        else
        {
            EEPROM_write(address, value);
            i++;
        }
    }


    return;

}